class ConqueredCastles extends UTTeamGame;

var array<ConObjective> ConMapObjectives;
var array<ConObjective> ConActiveObjectives;

var array<NavigationPoint> RecentlyUsedSpawns;

function PostBeginPlay()
{
	super.PostBeginPlay();
	ConFindObjectives();
}

// Kyle: Begin Pawn Handling

function AddDefaultInventory( pawn PlayerPawn )
{
	local ConPRI C;
	local UTWeapon UTW;
	local int AmmoToAdd;
	
	C = ConPRI (PlayerPawn.PlayerReplicationInfo);
	
	switch (C.ConClass)
	{
		case "Knight":
			// Kyle: Give Rocket Launcher
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_RocketLauncher')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 3);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			// Kyle: Give Link Gun
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_LinkGun')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 3);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			// Kyle: Give Stinger
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_Stinger')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 3);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			// Kyle: Give Enforcer
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_Enforcer')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 3);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			PlayerPawn.CreateInventory(class'UTGame.UTWeap_ImpactHammer');
			break;
		case "Scout":
			// Kyle: Give Link Gun
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_LinkGun')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 2);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			// Kyle: Give Stinger
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_Stinger')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 2);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			// Kyle: Give Enforcer
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_Enforcer')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 2);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			PlayerPawn.CreateInventory(class'UTGame.UTWeap_ImpactHammer');	
			break;
		case "Archer":
			// Kyle: Give Stinger
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_Stinger')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 1);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			// Kyle: Give Enforcer
				UTW = UTWeapon (UTPawn(PlayerPawn).CreateInventory(class'UTGame.UTWeap_Enforcer')); 
		        AmmoToAdd = (UTW.default.AmmoCount * 2);
		        if (UTW.default.AmmoCount + AmmoToAdd == 0) AmmoToAdd = 1 - UTW.default.AmmoCount; // At least 1 shot
		        UTW.AddAmmo (AmmoToAdd); // Automatically reduced by UT3
			PlayerPawn.CreateInventory(class'UTGame.UTWeap_ImpactHammer');	
			break;
	}

	PlayerPawn.AddDefaultInventory();
}

function ConRandomizeClasses()
{
	local string LastClass0;
	local string LastClass1;
	local Controller C;
	
	LastClass0 = "Knight";
	LastClass1 = "Knight";
	
	foreach WorldInfo.AllControllers(class'Controller', C)
	{
		if (ConPRI(C.PlayerReplicationInfo).Team.TeamIndex == 0)
		{
			switch (LastClass0)
			{
				case "Knight":
					ConPRI(C.PlayerReplicationInfo).ConClass = "Archer";
					LastClass0 = "Archer";
					break;
				case "Archer":
					ConPRI(C.PlayerReplicationInfo).ConClass = "Scout";
					LastClass0 = "Scout";
					break;
				case "Scout":
					ConPRI(C.PlayerReplicationInfo).ConClass = "Knight";
					LastClass0 = "Knight";
					break;
			}
		} else {
			switch (LastClass1)
			{
				case "Knight":
					ConPRI(C.PlayerReplicationInfo).ConClass = "Archer";
					LastClass1 = "Archer";
					break;
				case "Archer":
					ConPRI(C.PlayerReplicationInfo).ConClass = "Scout";
					LastClass1 = "Scout";
					break;
				case "Scout":
					ConPRI(C.PlayerReplicationInfo).ConClass = "Knight";
					LastClass1 = "Knight";
					break;
			}
		}
	}
}

// Kyle: End Pawn Handling

// Kyle: Begin Objective Handling

function ConFindObjectives()
{
	local ConObjective CO;
	
	foreach WorldInfo.AllNavigationPoints(class'ConObjective', CO)
	{
		ConMapObjectives.AddItem(CO);
	}
}

function ConSetObjectives()
{
	local int i;
	local ConObjective CO;
	
	for (i = 0; i < ConActiveObjectives.length; i++)
	{
		CO = ConActiveObjectives[i];
		ConActiveObjectives.RemoveItem(CO); // There has to be a way to do this in one line... 
	}
	
	for (i = 0; i < ConMapObjectives.length; i++)
	{		
		CO = ConMapObjectives[i];
		
		if (CO.ConAssociatedStage == ConGRI (WorldInfo.GRI).ConSiegePhase)
		{
			ConActiveObjectives.AddItem(CO);
		}
	}	
}

function SpawnSetCaptured(ConCaptureObjective_SpawnSets SpawnSet)
{
	local array<ConPlayerStart> Spawns;
	local int i;
	
	Spawns = SpawnSet.AssociatedPlayerStarts;
	
	for (i = 0; i < Spawns.length; i++)
	{		
		if (Spawns[i].TeamNumber == 1)
		{
			Spawns[i].TeamNumber = 0;	
		} else {
			Spawns[i].TeamNumber = 1;
		}
	}
}

function ObjectiveComplete(ConObjective Objective)
{
	ConActiveObjectives.RemoveItem(Objective);
	Objective.bConComplete = true;
	ConCheckPhase();
}

function ConCheckPhase()
{
	if (ConActiveObjectives.Length <= 0)
	{
		ConGRI(WorldInfo.GRI).ConSiegePhase ++;
		ConSetObjectives();
	}	
}

// Kyle: End Objective Handling

// Kyle: Begin Spawn Control Override

/** FindPlayerStart()
* Return the 'best' player start for this player to start from.  PlayerStarts are rated by RatePlayerStart().
* @param Player is the controller for whom we are choosing a playerstart
* @param InTeam specifies the Player's team (if the player hasn't joined a team yet)
* @param IncomingName specifies the tag of a teleporter to use as the Playerstart
* @returns NavigationPoint chosen as player start (usually a PlayerStart)
 */
function NavigationPoint FindPlayerStart( Controller Player, optional byte InTeam, optional string IncomingName )
{
	local NavigationPoint N, BestStart;
	local int i;
	local NavigationPoint CPS;
	
	// `log("CON: FindPlayerStart called");

	BestStart = ConChoosePlayerStart(Player, InTeam);

	if ( (BestStart == None) && (Player == None) )
	{
		// no playerstart found, so pick any NavigationPoint to keep player from failing to enter game
		`log("Warning - PATHS NOT DEFINED or NO PLAYERSTART with positive rating");
		ForEach AllActors( class 'NavigationPoint', N )
		{
			BestStart = N;
			break;
		}
	}
	
	if (RecentlyUsedSpawns.Length >= 10)
	{
		for (i = 0; i < RecentlyUsedSpawns.length; i++)
		{
			CPS = RecentlyUsedSpawns[i];		
			RecentlyUsedSpawns.RemoveItem(CPS);
		}
	}
	
	if (BestStart != none)
	{
		RecentlyUsedSpawns.AddItem(BestStart);
	}
	
	return BestStart;
}

/** ChoosePlayerStart()
* Return the 'best' player start for this player to start from.  PlayerStarts are rated by RatePlayerStart().
* @param Player is the controller for whom we are choosing a playerstart
* @param InTeam specifies the Player's team (if the player hasn't joined a team yet)
* @returns NavigationPoint chosen as player start (usually a PlayerStart)
 */
function ConPlayerStart ConChoosePlayerStart( Controller Player, optional byte InTeam )
{
	local ConPlayerStart P, BestStart;
	local float BestRating, NewRating;
	local byte Team;
	// `log("CON: ConChoosePlayerStart called");
	// use InTeam if player doesn't have a team yet
	Team = ( (Player != None) && (Player.PlayerReplicationInfo != None) && (Player.PlayerReplicationInfo.Team != None) )
			? byte(Player.PlayerReplicationInfo.Team.TeamIndex)
			: InTeam;

	// Find best playerstart
	foreach WorldInfo.AllNavigationPoints(class'ConPlayerStart', P)
	{
		NewRating = ConRatePlayerStart(P,Team,Player);
		if ( NewRating > BestRating )
		{
			BestRating = NewRating;
			BestStart = P;
		}
	}
	return BestStart;
}

/** RatePlayerStart()
* Return a score representing how desireable a playerstart is.
* @param P is the playerstart being rated
* @param Team is the team of the player choosing the playerstart
* @param Player is the controller choosing the playerstart
* @returns playerstart score
*/
function float ConRatePlayerStart(ConPlayerStart P, byte Team, Controller Player)
{	
	local float CurrentRating;
	
	// `log("CON: ConRatePlayerStart called");
	if ( !P.bEnabled )
		return 5;
		
	if (P.TeamNumber == Team)
	{
		if (Team == 0)
		{
			CurrentRating = P.ConTeam0Desire;
			
			If (P.ConClassPreference == ConPRI(Player.PlayerReplicationInfo).ConClass)
			{
				CurrentRating = CurrentRating +5;
			}
			
		} else {
			CurrentRating = P.ConTeam1Desire;
			
			If (P.ConClassPreference == ConPRI(Player.PlayerReplicationInfo).ConClass)
			{
				CurrentRating = CurrentRating +5;
			}	
		}
		
		if (RecentlyUsedSpawns.Find(P) != -1)
			{
				CurrentRating = CurrentRating - 3;
			}
			
		return CurrentRating;
	} else {
		return 5;
	}
}

// Kyle: End Spawn Control Override

// Kyle: Begin State Control Functions

function SetRoundFocus(Controller Winner)
{
	local PlayerController P;
	local UTPawn FP;

	FP = UTPawn(Winner.Pawn);

	if (Winner != none )
	{
		foreach WorldInfo.AllControllers(class'PlayerController', P)
		{
			P.SetCameraMode ('ThirdPerson');
			P.SetViewTarget(FP);
		}
	}
}

function StartNewSiege()
{
  local Controller C;
  ConInitRound();
    
  foreach WorldInfo.AllControllers(class'Controller', C) 
  {
	if (C != none && C.PlayerReplicationInfo != none && !C.PlayerReplicationInfo.bOnlySpectator) 
	{
		if (UTPlayerController(C) != None) 
		{
			UTPlayerController(C).bBehindView = false;
		}
		if(PlayerController(C) != none) PlayerController(C).ResetCameraMode();
		if(C.Pawn != None) C.Pawn.Destroy();
		
		// Kyle: GoToState('Dead'); has to be there or PlayerController's will be unable to move after ReStartPlayer for some reason
		C.GoToState('Dead');
		ReStartPlayer(C);
    }
  }
}

function ConInitRound()
{
	local ConObjective CO;
	local ConPlayerStart P;
	local int i;
	local ConGRI CGRI;
  
    CGRI = ConGRI (WorldInfo.GRI);

	foreach WorldInfo.AllNavigationPoints(class'ConPlayerStart', P)
	{
		P.Reset();
	}
	
	for (i = 0; i < ConMapObjectives.length; i++)
	{		
		CO = ConMapObjectives[i];
		CO.Reset();
	}
    CGRI.RemainingTimeRoundOffset = Max (0, CGRI.RemainingTime - CGRI.ConRoundLength);
    CGRI.bRoundIsOver = false;  
    CGRI.bKingIsDead = false;
    CGRI.ConRespawnTime = 1; // this ensures everyone spawns
    CGRI.ConSiegePhase = 0;
	
	ConTeamAI(Teams[0].AI).ConReset();
	ConTeamAI(Teams[1].AI).ConReset();
	ConSetObjectives();
	ConRandomizeClasses();
}

function bool CheckEndSiege(optional Controller Killer)
{
	local ConGRI CGRI;
	
	CGRI = ConGRI (WorldInfo.GRI);
	
	if ( (CGRI.bKingIsDead == true || CGRI.RemainingRoundTime <= 0) && CGRI.bRoundIsOver == false )
	{
		Teams[0].Score += 1;
		Countdown = 8;
		if (Killer != none)	SetRoundFocus(Killer);
		CGRI.bRoundIsOver = true;
		GoToState ('BetweenRounds');
		return true;
	} else {
		return false;
	}
}

// Kyle: End State Control Functions

// Kyle: Begin Spawn Control Functions

function RestartPlayer(Controller NewPlayer)
{
	local ConPRI CPRI;
	CPRI = ConPRI (NewPlayer.PlayerReplicationInfo);
	
  if (CPRI.bRecentlyDead != true)
  {
    ConPRI (NewPlayer.PlayerReplicationInfo).bConDead = false;
    Super.RestartPlayer(NewPlayer);
  }
}

// Kyle: End Spawn Control Functions

// Kyle: Begin Team Functions

// Kyle: End Team Functions

// Kyle: Begin Score Functions

function ScoreKill(Controller Killer, Controller Other)
{
	local ConPRI KillerPRI;
	// local ConPRI OtherPRI;

	KillerPRI = ConPRI(Killer.PlayerReplicationInfo);
	// OtherPRI = ConPRI(Other.PlayerReplicationInfo);

	KillerPRI.Score += 1;

	// check score - change this to be a check to see if victim=king

	if ( (Killer != none) && bScoreTeamKills )
		CheckScore(Killer.PlayerReplicationInfo);
	
}

/*
function bool CheckScore(PlayerRelicationInfo Scorer)
{

}
*/

// Kyle: End Score Functions


// Kyle: Begin State Declaration

State MatchInProgress
{	
	event Timer()
	{
		Super.Timer();
	}
}

auto State BetweenRounds
{
	function BeginState(Name PreviousStateName)
	{
		local Controller C;
		
		foreach WorldInfo.AllControllers(class'Controller', C)
		{
			// C.GotoState('RoundEnded');
		}		
	}
	
	function EndState(Name NextStateName)
	{
		StartNewSiege();
	}
	
	function Timer()
	{
		CountDown--;
		if (CountDown <= 0 )
			GotoState('MatchInProgress');
		else
			StartupStage = CountDown + 10;
		if (CountDown < 6) PlayStartupMessage(); //5 4 3 2 1
	}
}

auto State PendingMatch
{
  function EndState(Name NextStateName)
  {
    StartNewSiege();
    Super.EndState (NextStateName);
  }

	function Timer()
	{
		local PlayerController P;
		local bool bReady;
		local UTBot B;

		Global.Timer();

		// first check if there are enough net players, and enough time has elapsed to give people
		// a chance to join
		if ( NumPlayers == 0 )
		{
			bWaitForNetPlayers = true;

			if (bWarmupRound)
			{
				WarmupRemaining = WarmupTime;
				GameReplicationInfo.RemainingTime = WarmupRemaining;
			}
		}
		else
		{
			foreach WorldInfo.AllControllers(class'UTBot', B)
			{
				if (TooManyBots(B))
				{
					B.Destroy();
				}
			}

			AddInitialBots();

			if (bWarmupRound)
			{
				if (WarmupRemaining > 0)
				{
					WarmupRemaining--;
					GameReplicationInfo.RemainingTime = WarmupRemaining;
					if (WarmupRemaining % 60 == 0)
					{
						GameReplicationInfo.RemainingMinute = WarmupRemaining;
					}
			   		return;
				}
				else if (WarmupRemaining == 0)
				{
					WarmupRemaining = -1;
					UTGameReplicationInfo(GameReplicationInfo).bWarmupRound = false;
			   		ResetLevel();
				}
			}
		}

		if ( bWaitForNetPlayers && (WorldInfo.NetMode != NM_Standalone) )
		{
			if ( (NumPlayers >= MinNetPlayers) && (NumPlayers > 0) )
				PendingMatchElapsedTime++;
			else
				PendingMatchElapsedTime = 0;
			if ( (NumPlayers == MaxPlayers) || (PendingMatchElapsedTime > NetWait) )
			{
				// wait until players finish clientside processing (or it times out)
				if (PendingMatchElapsedTime <= ClientProcessingTimeout)
				{
					if (!InitialProcessingIsComplete())
					{
						PlayStartupMessage();
						return;
					}
				}
				bWaitForNetPlayers = false;
				CountDown = Default.CountDown;
			}
			else
			{
				PlayStartupMessage();
				return;
			}
		}
		else if (WorldInfo.NetMode == NM_Standalone && !InitialProcessingIsComplete())
		{
			// PlayStartupMessage() intentionally left out here (mesh construction messsage should be visible)
			return;
		}

		// check if players are ready
		bReady = true;

		StartupStage = 1;
		if ( !bStartedCountDown && (bPlayersMustBeReady || (WorldInfo.NetMode == NM_Standalone)) )
		{
			foreach WorldInfo.AllControllers(class'PlayerController', P)
			{
				if ( P.PlayerReplicationInfo != None && P.bIsPlayer && P.PlayerReplicationInfo.bWaitingPlayer
					&& !P.PlayerReplicationInfo.bReadyToPlay )
				{
					bReady = false;
				}
			}
		}
		if ( bReady && SinglePlayerMissionID == INDEX_None )
		{

			if (!bStartedCountDown)
			{
				if (DemoPrefix != "")
				{
					ConsoleCommand("demorec" @ DemoPrefix $ "-%td");
				}
				bStartedCountDown = true;
			}
			CountDown--;
			if ( CountDown <= 0 )
				StartMatch();
			else
				StartupStage = CountDown + 10;
		}
		if (Countdown < 6) PlayStartupMessage(); // 5 4 3 2 1 
	}
}	

// Kyle: End State Declaration

// Kyle: Begin Stripped Functions

exec function AddRedBots(int Num)
{
}

exec function AddBlueBots(int Num)
{
}

function bool TooManyBots(Controller botToRemove)
{
	return false;
}

// Kyle: End Stripped Functions

DefaultProperties
{
	bMustJoinBeforeStart=false
	bTeamGame=true
	bMustHaveMultiplePlayers=false
	PlayerControllerClass=class'ConPlayerController'
	PlayerReplicationInfoClass=class'ConPRI'
	GameReplicationInfoClass=class'ConGRI'
	DefaultPawnClass=class'ConPawn'
	HUDType=class'ConHUD'
	Description="Tower Defense."
	GameName="ConqueredCastles"
	MapPrefixes[1]="CTF"
	MapPrefixes[2]="CON"
	Acronym="CON"
	bOverTime=false;
	
	TeamAIType(0)=class'ConTeamAI'
	TeamAIType(1)=class'ConTeamAI'
	BotClass=class'ConAIController'
}

